<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Unit tests for tinymce.EditorCommands</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
<script src="qunit/connector.js"></script>
<script type="text/javascript" src="qunit/runner.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/tiny_mce_loader.js"></script>
<script>
var editor;

QUnit.config.reorder = false;
QUnit.config.autostart = false;
module("tinymce.EditorCommands", {
	autostart: false
});

function getContent() {
	return editor.getContent({format:'raw'}).toLowerCase().replace(/[\r\n]+/g, '');
};

test('mceInsertContent - p inside text of p', function() {
	var rng;
	
	expect(7);

	editor.setContent('<p>1234</p>');
	editor.focus();
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 3);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<p>abc</p>');
	equals(getContent(), '<p>1</p><p>abc</p><p>4</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - p inside whole p', function() {
	var rng;

	expect(7);

	editor.setContent('<p>1234</p>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 0);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<p>abc</p>');
	equals(getContent(), '<p>abc</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - pre in text of pre', function() {
	var rng;
	
	expect(7);

	editor.setContent('<pre>1234</pre>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('pre')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('pre')[0].firstChild, 3);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<pre>abc</pre>');
	equals(getContent(), '<pre>1</pre><pre>abc</pre><pre>4</pre>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'PRE');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'PRE');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - h1 in text of h1', function() {
	var rng;
	
	expect(7);

	editor.setContent('<h1>1234</h1>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('h1')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('h1')[0].firstChild, 3);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<h1>abc</h1>');
	equals(getContent(), '<h1>1</h1><h1>abc</h1><h1>4</h1>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'H1');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'H1');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - li inside li', function() {
	var rng;
	
	expect(7);

	editor.setContent('<ul><li>1234</li></ul>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('li')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('li')[0].firstChild, 3);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<li>abc</li>');
	equals(getContent(), '<ul><li>1</li><li>abc</li><li>4</li></ul>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'LI');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'LI');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - p inside empty editor', function() {
	var rng;

	expect(7);

	editor.setContent('');
	editor.execCommand('mceInsertContent', false, '<p>abc</p>');
	equals(getContent(), '<p>abc</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - text inside empty p', function() {
	var rng;

	expect(7);

	editor.getBody().innerHTML = '<p></p>';
	setSelection('p', 0);
	editor.execCommand('mceInsertContent', false, 'abc');
	equals(editor.getBody().innerHTML.toLowerCase().replace(/^<br>/, ''), '<p>abc</p>'); // Opera inserts a BR at the beginning of contents if the P is empty
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - text inside empty p with br caret node', function() {
	var rng;

	expect(7);

	editor.getBody().innerHTML = '<p><br></p>';
	rng = editor.dom.createRng();
	rng.setStart(editor.getBody().firstChild, 0);
	rng.setEnd(editor.getBody().firstChild, 0);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, 'abc');
	equals(editor.getBody().innerHTML.toLowerCase(), '<p>abc</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
	equals(rng.startContainer.innerHTML, 'abc');
});

test('mceInsertContent - image inside p', function() {
	var rng;
	
	expect(6);

	editor.setContent('<p>1</p>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 0);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 1);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<img src="about:blank" />');
	equals(editor.getContent(), '<p><img src="about:blank" alt="" /></p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 1);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 1);
});

test('mceInsertContent - legacy content', function() {
	var rng;
	
	expect(1);

	// Convert legacy content
	editor.setContent('<p>1</p>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 0);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 1);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<u>u</u><strike>strike</strike><font size="7">font</font>');
	equals(editor.getContent(), '<p><span style="text-decoration: underline;">u</span><span style="text-decoration: line-through;">strike</span><span style="font-size: 300%;">font</span></p>');
});

test('mceInsertContent - hr', function() {
	var rng;
	
	expect(7);

	editor.setContent('<p>123</p>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, '<hr />');
	equals(editor.getContent(), '<p>1</p><hr /><p>3</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer, editor.getBody().lastChild);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 0);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 0);
});

test('mceInsertContent - forced root block', function() {
	var rng;
	
	expect(1);

	// Forced root block
	editor.getBody().innerHTML = '';
	editor.execCommand('mceInsertContent', false, 'test<b>123</b><!-- a -->');
	// Opera adds an extra paragraph since it adds a BR at the end of the contents pass though this for now since it's an minority browser
	equals(editor.getContent().replace(/<p>\u00a0<\/p>/g, ''), '<p>test<strong>123</strong></p><!-- a -->');
});

test('mceInsertContent - mixed inline content inside td', function() {
	var rng;
	
	expect(1);

	// Forced root block
	editor.getBody().innerHTML = '<table><tr><td>X</td></tr></table>';
	setSelection('td', 0, 'td', 0);
	editor.execCommand('mceInsertContent', false, 'test<b>123</b><!-- a -->');
	equals(editor.getContent(), '<table><tbody><tr><td>test<strong>123</strong><!-- a -->X</td></tr></tbody></table>');
});

test('mceInsertContent - invalid insertion with spans on page', function(){
	var startingContent = '<p>123 testing <span>span later in document</span></p>',
		insertedContent = '<ul><li>u</li><li>l</li></ul>';
	editor.setContent(startingContent);
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 0);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 0);
	editor.selection.setRng(rng);
	editor.execCommand('mceInsertContent', false, insertedContent);

	equals(editor.getContent(), insertedContent + startingContent);
});

test('InsertHorizontalRule', function() {
	var rng;
	
	expect(7);

	editor.setContent('<p>123</p>');
	rng = editor.dom.createRng();
	rng.setStart(editor.dom.select('p')[0].firstChild, 1);
	rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
	editor.selection.setRng(rng);
	editor.execCommand('InsertHorizontalRule');
	equals(editor.getContent(), '<p>1</p><hr /><p>3</p>');
	rng = normalizeRng(editor.selection.getRng(true));
	ok(rng.collapsed);
	equals(rng.startContainer, editor.getBody().lastChild);
	equals(rng.startContainer.nodeName, 'P');
	equals(rng.startOffset, 0);
	equals(rng.endContainer.nodeName, 'P');
	equals(rng.endOffset, 0);
});

tinyMCE.init({
	mode : "exact",
	elements : "elm1",
	theme : "advanced",
	add_unload_trigger : false,
	apply_source_formatting : false,
	entities : 'raw',
	convert_urls : false,
	valid_styles : {
		'*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
	},
	init_instance_callback : function(ed) {
		editor = ed;

		ed.onNodeChange.addToTop(function() {
			return false;
		});

		QUnit.start();
	}
});
</script>
</head>
<body>
	<h1 id="qunit-header">Unit tests for tinymce.EditorCommands</h1>
	<h2 id="qunit-banner"></h2>
	<div id="qunit-testrunner-toolbar"></div>
	<h2 id="qunit-userAgent"></h2>
	<ol id="qunit-tests"></ol>
	<textarea id="elm1" name="elm1"></textarea>
	<div>
		<a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
		<a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
	</div>
</body>
</html>
